package com.wiscamp.ninechapters.problems.math;

import java.util.Collection;

/**
 * 数学式子工具类
 */
public class SentenceUtils {

    private SentenceUtils() {
    }

    /**
     * 比较表达式各项是否相同
     *
     * @param sourceTerms 原项列表
     * @param targetTerms 目标项列表
     * @return 如果完全相同，返回true
     */
    public static boolean sameTerms(Collection<String> sourceTerms, Collection<String> targetTerms) {
        Collection<String> terms = sourceTerms;
        Collection<String> otherTerms = targetTerms;
        if (terms.size() != otherTerms.size()) return false;
        for (var term : terms) {
            boolean hasFound = existsInTerms(term, otherTerms);
            if (!hasFound) return false;
        }
        for (var term : otherTerms) {
            boolean hasFound = existsInTerms(term, terms);
            if (!hasFound) return false;
        }
        return true;
    }

    /**
     * 比较两个不含变量的表达式的计算结果是否相同
     *
     * @param exp1 原表达式
     * @param exp2 目标表达式
     * @return 如果两个表达式结果完全相同，返回true
     */
    public static boolean sameResult(String exp1, String exp2) {
        var tempStr1 = exp1.replace(" ", "").trim();
        var tempStr2 = exp2.replace(" ", "").trim();

        if (tempStr1.equals(tempStr2)) return true;

        var parse1 = new org.nfunk.jep.JEP();
        var parse2 = new org.nfunk.jep.JEP();
        parse1.parseExpression(tempStr1);
        parse2.parseExpression(tempStr2);
        var result1 = parse1.getValue();
        var result2 = parse2.getValue();
        return result1 == result2;
    }


    private static boolean existsInTerms(String termText, Collection<String> terms) {
        for (var term : terms) {
            if (termText.equals(term))
                return true;
        }
        return false;
    }

    /**
     * 根据表达式文本创建不同类型的表达式
     *
     * @param expression 表达式文本
     * @return
     */
    public static LatexText getExpressionLatexText(String expression) {
        var hasPlusMinus = expression.contains(ArithmeticOperators.PLUS) || expression.contains(ArithmeticOperators.MINUS);
        var hasTimesDivision = expression.contains(ArithmeticOperators.TIMES) || expression.contains(ArithmeticOperators.DIVISION);
        if (hasTimesDivision && hasPlusMinus) {
            return new LatexArithmeticExpression(expression);
        } else if (hasTimesDivision) {
            return new LatexTimesDivisionExpression(expression);
        } else if (hasPlusMinus) {
            return new LatexPlusMinusExpression(expression);
        }
        return new LatexText(expression, LatexTextEnum.GENERAL);
    }

    /**
     * 根据表达式文本创建不同类型的等式
     *
     * @param equation 表达式文本
     * @return
     */
    public static LatexText getEquationLatexText(String equation) {
        var hasPlusMinus = equation.contains(ArithmeticOperators.PLUS) || equation.contains(ArithmeticOperators.MINUS);
        var hasTimesDivision = equation.contains(ArithmeticOperators.TIMES) || equation.contains(ArithmeticOperators.DIVISION);
        if (hasTimesDivision && hasPlusMinus) {
            return new LatexArithmeticEquation(equation);
        } else if (hasTimesDivision) {
            return new LatexTimesDivisionEquation(equation);
        } else if (hasPlusMinus) {
            return new LatexPlusMinusEquation(equation);
        }
        return new LatexText(equation, LatexTextEnum.GENERAL);
    }

    public static LatexText getInequalityLatexText(String equation) {
        var hasPlusMinus = equation.contains(ArithmeticOperators.PLUS) || equation.contains(ArithmeticOperators.MINUS);
        var hasTimesDivision = equation.contains(ArithmeticOperators.TIMES) || equation.contains(ArithmeticOperators.DIVISION);
        if (hasTimesDivision && hasPlusMinus) {
            return new LatexArithmeticInequality(equation);
        } else if (hasTimesDivision) {
            return new LatexTimesDivisionInequality(equation);
        } else if (hasPlusMinus) {
            return new LatexPlusMinusInequality(equation);
        }
        return new LatexText(equation, LatexTextEnum.GENERAL);
    }

    public static boolean hasVariable(String expression) {
        if (expression.contains("x") || expression.contains("y") || expression.contains("z") ||
                expression.contains("a") || expression.contains("b") || expression.contains("c")) {
            return true;
        }
        return false;
    }

    /**
     * 比较两个表达式是否完全相同
     *
     * @param exp1 原表达式
     * @param exp2 目标表达式
     * @return 如果各项相同且计算结果相同，返回true
     */
    public static boolean equalsExpression(String exp1, String exp2) {
        LatexText text1 = getExpressionLatexText(exp1);
        LatexText text2 = getExpressionLatexText(exp2);
        var terms1 = text1.toTerms();
        var terms2 = text2.toTerms();
        if (sameTerms(terms1, terms2)) {
            if (!hasVariable(exp1) && !hasVariable(exp2)) {
                if (sameResult(exp1, exp2))
                    return true;
                else
                    return false;
            }
            return true;
        }
        return false;
    }

    public static boolean equalEquation(String equation1, String equation2) {
        if (!equation1.contains("=") || !equation2.contains("="))
            return false;

        var leftExpressionInEquation1 = equationToExpression(equation1, true);
        var rightExpressionInEquation1 = equationToExpression(equation1, false);
        var leftExpressionInEquation2 = equationToExpression(equation2, true);
        var rightExpressionInEquation2 = equationToExpression(equation2, false);

        if ("".equals(leftExpressionInEquation1) ||
                "".equals(leftExpressionInEquation2) ||
                "".equals(rightExpressionInEquation1) ||
                "".equals(rightExpressionInEquation2))
            return false;

        if (equalsExpression(leftExpressionInEquation1, leftExpressionInEquation2)) {
            if (equalsExpression(rightExpressionInEquation1, rightExpressionInEquation2))
                return true;
            else
                return false;
        } else {
            if (equalsExpression(leftExpressionInEquation1, rightExpressionInEquation2)) {
                if (equalsExpression(rightExpressionInEquation1, leftExpressionInEquation2))
                    return true;
                else
                    return false;
            }
        }

        return false;
    }

    public static String equationToExpression(String equation, boolean returnLeftExpression) {
        var array = equation.split("=");
        if (array.length != 2) return "";

        var leftExpression = array[0].trim();
        var rightExpression = array[1].trim();

        if (returnLeftExpression)
            return leftExpression;
        else
            return rightExpression;

    }

}
